package top.haijunit.work.utils;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToLongFunction;
import java.util.stream.Collectors;

/**
 * stream的封装工具类
 *
 * @author zhanghaijun
 * @since 2024-08-20
 */
@Slf4j
@UtilityClass
public class StreamUtils {

    /**
     * 集合转换为 Map
     *
     * @param collection    集合对象
     * @param keyMapper     Key的映射规则
     * @param valueMapper   value映射规则
     * @param mergeFunction 合并规则
     * @param <K>           Key的泛型
     * @param <E>           集合元素类型的泛型
     * @param <V>           最终输出类型的泛型
     * @return Map<K, V>
     */
    public static <K, E, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> keyMapper, Function<E, V> valueMapper, BinaryOperator<V> mergeFunction) {
        if (collection == null) {
            return new HashMap<>();
        }
        return collection.stream().collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new));
    }

    public static <K, E, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> keyMapper, Function<E, V> valueMapper) {
        return toMap(collection, keyMapper, valueMapper, (v1, v2) -> v1);
    }

    public static <K, E> Map<K, E> toMap(Collection<E> collection, Function<E, K> keyMapper) {
        return toMap(collection, keyMapper, Function.identity());
    }

    /**
     * 把流中的某一元素用连接标志连接成一个字符串.
     *
     * @param stream   流.
     * @param func     函数.
     * @param joinFlag 连接标志.
     * @param <T>      函数的入参.
     * @return String.
     */
    public static <T> String join(Collection<T> collection, Function<T, String> func, String joinFlag) {
        return collection.stream().map(func).collect(Collectors.joining(joinFlag));
    }

    /**
     * 从流中抽取<R>，生成字符串数组.
     *
     * @param stream 流.
     * @param func   传入的函数.
     * @param <T>    函数的入参.
     * @return List<R>.
     */
    public static <T> String[] mapToStrArray(Collection<T> collection, Function<T, String> func) {
        return collection.stream().map(func).toArray(String[]::new);
    }

    /**
     * 从流中抽取<R>，生成集合List<R>.
     *
     * @param stream 流.
     * @param func   传入的函数.
     * @param <T>    函数的入参.
     * @param <R>    函数的出参.
     * @return List<R>.
     */
    public static <T, R> List<R> mapToList(Collection<T> collection, Function<T, R> func) {
        return collection.stream().map(func).toList();
    }

    /**
     * 从流中抽取<R>，生成去重集合Set<R>.
     *
     * @param stream 流.
     * @param func   传入的函数.
     * @param <T>    函数的入参.
     * @param <R>    函数的出参.
     * @return Set<R>.
     */
    public static <T, R> Set<R> mapToSet(Collection<T> collection, Function<T, R> func) {
        return collection.stream().map(func).collect(Collectors.toSet());
    }

    /**
     * 从流中抽取<R>，生成Map<R,T>.
     *
     * @param stream 流.
     * @param func   传入的函数.
     * @param <T>    函数的入参.
     * @param <R>    函数的出参.
     * @return Map<R, T>.
     */
    public static <T, R> Map<R, T> identity(Collection<T> collection, Function<T, R> func) {
        return collection.stream().collect(Collectors.toMap((func), Function.identity()));
    }

    /**
     * 从流中抽取<R>，根据R的不同值生成Map<R,List<T>>.
     *
     * @param stream 流.
     * @param func   传入的函数.
     * @param <T>    函数的入参.
     * @param <R>    函数的出参.
     * @return Map<R, List < T>>.
     */
    public static <T, R> Map<R, List<T>> groupBy(Collection<T> collection, Function<T, R> func) {
        return collection.stream().collect(Collectors.groupingBy(func));
    }

    /**
     * 从流中抽取满足条件函数predicate的元素，生成List<T>.
     *
     * @param stream    流.
     * @param predicate 返回boolean的函数.
     * @param <T>       函数的入参.
     * @return List<T>.
     */
    public static <T> List<T> filter(Collection<T> collection, Predicate<T> predicate) {
        if (null == collection) {
            return new ArrayList<>();
        }
        return collection.stream().filter(predicate).toList();
    }

    /**
     * 从流中抽取满足条件函数predicate的元素，选取第一个.
     *
     * @param stream    流.
     * @param predicate 返回boolean的函数.
     * @param t         没有第一个默认，指定返回.
     * @param <T>       函数的入参.
     * @return List<T>.
     */
    public static <T> T filterFirst(Collection<T> collection, Predicate<T> predicate, T t) {
        return collection.stream().filter(predicate).findFirst().orElse(t);
    }

    /**
     * 从流中抽取满足条件函数predicate的元素，生成List<T>.
     *
     * @param stream    流.
     * @param predicate 返回boolean的函数.
     * @param <T>       函数的入参.
     * @return List<T>.
     */
    public static <T> List<T> filterSort(Collection<T> collection, Predicate<T> predicate, Comparator<T> comparator) {
        return collection.stream().filter(predicate).sorted(comparator).toList();
    }


    /**
     * 从流中抽取满足条件函数predicate的元素，并按func的出参进行排序，生成有序List<T>.
     *
     * @param stream    流.
     * @param predicate 条件函数.
     * @param func      函数.
     * @param <T>       条件函数的入参.
     * @param <U>       函数的出参.
     * @return List<T>.
     */
    public static <T, U extends Comparable<? super U>> List<T> filterSort(Collection<T> collection, Predicate<T> predicate, Function<T, U> func) {
        return collection.stream().filter(predicate).sorted(Comparator.comparing(func)).toList();
    }

    /**
     * 统计流中某项类型为Long的元素之和.
     *
     * @param stream 流.
     * @param func   函数.
     * @param <T>    函数的入参.
     * @return Long.
     */
    public static <T> Long filterSumLong(Collection<T> collection, ToLongFunction<T> func) {
        return collection.stream().filter(Objects::nonNull).mapToLong(func).sum();
    }

    /**
     * 统计流中某项类型为BigDecimal的元素之和.
     *
     * @param stream 流.
     * @param func   函数.
     * @param <T>    函数的入参.
     * @return BigDecimal.
     */
    public static <T> BigDecimal filterSumBigDecimal(Collection<T> collection, Function<T, BigDecimal> func) {
        return collection.stream().filter(Objects::nonNull).map(func).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 从流中抽取满足条件函数predicate的元素，并返回元素数量.
     *
     * @param stream    流.
     * @param predicate 条件函数.
     * @param <T>       函数的入参.
     * @return List<T>.
     */
    public static <T> long count(Collection<T> collection, Predicate<T> predicate) {
        return collection.stream().filter(predicate).count();
    }

    /**
     * 统计流中<R>的不同类型的数量.
     *
     * @param stream 流.
     * @param func   函数.
     * @param <T>    函数的入参.
     * @param <R>    函数的出参.
     * @return List<T>.
     */
    public static <T, R> Map<R, Long> mapCount(Collection<T> collection, Function<T, R> func) {
        return collection.stream().collect(Collectors.groupingBy(func, Collectors.counting()));
    }

    /**
     * 流中的元素按比较函数排序，选出最大的元素。无，则手动返回.
     *
     * @param stream     流.
     * @param comparator 比较函数.
     * @param obj        当没有找到最大元素的返回值.
     * @param <T>        函数的入参.
     * @return List<T>.
     */
    public static <T> T max(Collection<T> collection, Comparator<T> comparator, T obj) {
        return collection.stream().max(comparator).orElse(obj);
    }

    /**
     * 如果流中有任一元素满足条件predicate，则返回true,反之，则返回false.
     *
     * @param stream    流.
     * @param predicate 条件函数.
     * @param <T>       函数的入参.
     * @return boolean.
     */
    public static <T> boolean anyMatch(Collection<T> collection, Predicate<T> predicate) {
        return collection.stream().anyMatch(predicate);
    }
}
